﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows.Data;
using System.Linq;

namespace MoneyManagerNET.Presentation.ViewModel
{
    using Model;
using System.Windows.Input;
    using MoneyManagerNET.Presentation.ViewModel.Base;
    
    
    public class BankAccountViewModel:ViewModelBase<IBankAccount>
    {

        public String Name { get { return (ModelAs==null)?"<all accounts>":ModelAs.Name; } }

        public decimal AccountBalance
        { 
            get {
                return (ModelAs==null)?App.Storage.Select<IBankAccount>().Sum(acc=>acc.GetAccountBalance()):ModelAs.GetAccountBalance();
            }
        }

        public decimal ReconciledBalance {
            get {
                return (ModelAs == null) ? App.Storage.Select<IBankAccount>().Sum(acc => acc.GetReconciledBalance()) : ModelAs.GetReconciledBalance();
            }
        }

        ObservableCollection<ITransaction> _transactionSource;
        public ObservableCollection<ITransaction> TransactionSource { 
            get { return _transactionSource; }
            set { _transactionSource = value; this.OnChange(() => TransactionSource); Transactions = TransactionSource == null ? null : CollectionViewSource.GetDefaultView(TransactionSource); } 
        }

        ICollectionView _transactions = null;
        public ICollectionView Transactions
        {
            get { return _transactions; }
            protected set { _transactions = value; this.OnChange(() => Transactions); }
        }

        public ITransaction Selected { get { return Transactions.CurrentItem as ITransaction; } set {if(Transactions!=null) Transactions.MoveCurrentTo(value); } }



        public override object Model
        {

            get
            {
                return base.Model;
            }
            set
            {
                base.Model = value;

                if (ModelAs == null)
                {
                    TransactionSource = new ObservableCollection<ITransaction>(App.Storage.Select<ITransaction>()); ;
                }
                else 
                {
                    var allTransactions = ModelAs.GetAllTransactions();
                   TransactionSource = new ObservableCollection<ITransaction>(allTransactions);
                    
                }
            }
        }

       
        public BankAccountViewModel()
        {
            EditCommand = new Infrastructure.DelegateCommand(PromptForEditCurrent,o=>true);
            NewCommand = new Infrastructure.DelegateCommand(PromptForNew,o=>true);
            DeleteCommand=new Infrastructure.DelegateCommand(o=>DeleteCurrent(),o=>true);
            MoveCommand = new Infrastructure.DelegateCommand(o=>MoveCurrent(),o=>true);
        }

        public ICommand NewCommand { get;protected set; }
        public void PromptForNew(object o)
        {
            var transaction =App.Storage.New<ITransaction>();
            transaction.Status = (byte)TransactionStatus.Followup;

            TransactionViewModel vm = new TransactionViewModel();
            vm.ContextAccount = ModelAs;
            vm.ModelAs = transaction;
            vm.TransactionType = TransactionType.Deposit;

            var r = vm.ShowDialog();

            if (r.HasValue && r.Value)
            {
                TransactionSource.Add(transaction);
                this.OnChange(() => AccountBalance);
                this.OnChange(() => ReconciledBalance);

                App.Storage.SaveAll();
            }

        }


        public ICommand EditCommand { get;protected set; }
        public void PromptForEditCurrent(object o)
        {
            var transaction=this.Selected;

            TransactionViewModel vm = new TransactionViewModel();
            vm.ContextAccount = this.ModelAs;
            vm.ModelAs = transaction;


            var r = vm.ShowDialog();

            if (r.HasValue && r.Value)
            {
                vm.PutValues(transaction);
                Transactions.Refresh();
                this.OnChange(() => AccountBalance);
                this.OnChange(() => ReconciledBalance);
            }
        }

        public ICommand DeleteCommand { get; protected set; }
        public void DeleteCurrent()
        {
            var transaction = Selected;
            if (transaction == null) return;
            var current = this.Selected;
            App.Storage.Delete(transaction);
            TransactionSource.Remove(current);
            this.OnChange(() => AccountBalance);
            this.OnChange(() => ReconciledBalance);
        }


        public ICommand MoveCommand { get; protected set; }
        public void MoveCurrent() {
            var vm = new AccountListViewModel();
            var r = vm.ShowDialog();
            var transaction=Selected;
            if (r.HasValue && r.Value) {
                var newAccount=vm.Selected;
 
                if(ModelAs==transaction.FromAccount)
                    transaction.FromAccount=newAccount;
                if(ModelAs==transaction.ToAccount)
                    transaction.ToAccount=newAccount;

                TransactionSource.Remove(transaction);
                this.OnChange(() => AccountBalance);
                this.OnChange(() => ReconciledBalance);
            }
        }



        public bool CanCreateNew {
            get { return ModelAs != null; }
        }

        #region filters

        TransactionFilter[] _filters;
        public TransactionFilter[] FilterList { 
            get {
                if (_filters == null) {
                    var fList = new List<TransactionFilter>();
                    fList.Add(new TransactionFilter("all", transaction => true));
                    fList.Add(new TransactionFilter("within 24 hours", transaction => (DateTime.Now-transaction.Date).TotalHours<24));
                    fList.Add( new TransactionFilter( "this week",transaction=>(transaction.Date>(DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek)))));//+-1
                    fList.Add( new TransactionFilter( "last 30 days",transaction=>(DateTime.Today- transaction.Date).TotalDays<30));
                    _filters = fList.ToArray();
                }
                return _filters;
                } 
        }

        TransactionFilter _filter;
        public TransactionFilter Filter { get { return _filter; } set { _filter = value; Transactions.Filter = o => Filter.Predicate((ITransaction)o); this.OnChange(() => Filter); this.OnChange(() => Transactions); } }


        public class TransactionFilter {
            public TransactionFilter(string title,Predicate<ITransaction> predicate)
            {
                this.Title = title;
                this.Predicate = predicate;
            }
            public string Title { get; set; }
            public Predicate<ITransaction> Predicate;
            public override string ToString()
            {
                return Title;
            }
        }

        #endregion

    }
}
